home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / ODFDev / ODF / Framewrk / FWPart / FWLnkMgr.cpp < prev    next >
Encoding:
Text File  |  1996-09-17  |  36.4 KB  |  1,209 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                FWLnkMgr.cpp
  4. //    Release Version:    $ ODF 2 $
  5. //
  6. //    Copyright:            (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWFrameW.hpp"
  11.  
  12. #ifndef FWLNKMGR_H
  13. #include "FWLnkMgr.h"
  14. #endif
  15.  
  16. // ----- Framework Includes -----
  17.  
  18. #ifndef FWPART_H
  19. #include "FWPart.h"
  20. #endif
  21.  
  22. #ifndef FWPRESEN_H
  23. #include "FWPresen.h"
  24. #endif
  25.  
  26. #ifndef FWLNKITE_H
  27. #include "FWLnkIte.h"
  28. #endif
  29.  
  30. #ifndef FWUTIL_H
  31. #include "FWUtil.h"
  32. #endif
  33.  
  34. #ifndef FWCLNINF_H
  35. #include "FWClnInf.h"
  36. #endif
  37.  
  38. #ifndef FWLNKCMD_H
  39. #include "FWLnkCmd.h"
  40. #endif
  41.  
  42. #ifndef FWSESION_H
  43. #include "FWSesion.h"
  44. #endif
  45.  
  46. #ifndef FWLINK_K
  47. #include "FWLink.k"
  48. #endif
  49.  
  50. // ----- Foundation Includes -----
  51.  
  52. #ifndef FWPRIDEB_H
  53. #include "FWPriDeb.h"
  54. #endif
  55.  
  56. #ifndef FWMEMMGR_H
  57. #include "FWMemMgr.h"
  58. #endif
  59.  
  60. #ifndef FWBARRAY_H
  61. #include "FWBArray.h"
  62. #endif
  63.  
  64. // ----- OS Includes -----
  65.  
  66. #ifndef FWTIME_H
  67. #include "FWTime.h"
  68. #endif
  69.  
  70. #ifndef FWSUUTIL_H
  71. #include "FWSUUtil.h"
  72. #endif
  73.  
  74. #ifndef FWCFMRES_H
  75. #include "FWCFMRes.h"
  76. #endif
  77.  
  78. // For FW_kUndoPasteAsMsg
  79. #ifndef SLODFSTR_K
  80. #include "SLODFStr.k"
  81. #endif
  82.  
  83. // For FW_PrivLoadODFString
  84. #ifndef SLODFSTR_H
  85. #include "SLODFStr.h"
  86. #endif
  87.  
  88. // ----- OpenDoc Includes -----
  89.  
  90. #ifndef SOM_Module_OpenDoc_StdProps_defined
  91. #include <StdProps.xh>
  92. #endif
  93.  
  94. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  95. #include <StdTypes.xh>
  96. #endif
  97.  
  98. #ifndef SOM_ODStorageUnit_xh
  99. #include <StorageU.xh>
  100. #endif
  101.  
  102. #ifndef SOM_ODDraft_xh
  103. #include <Draft.xh>
  104. #endif
  105.  
  106. #ifndef SOM_ODClipboard_xh
  107. #include <Clipbd.xh>
  108. #endif
  109.  
  110. #ifndef SOM_ODLink_xh
  111. #include <Link.xh>
  112. #endif
  113.  
  114. #ifndef SOM_ODLinkSpec_xh
  115. #include <LinkSpec.xh>
  116. #endif
  117.  
  118. #ifndef SOM_ODLinkSource_xh
  119. #include <LinkSrc.xh>
  120. #endif
  121.  
  122. #if defined(FW_BUILD_MAC) && !defined(__DIALOGS__)
  123. #include <Dialogs.h>
  124. #endif
  125.  
  126. //========================================================================================
  127. //    Runtime information
  128. //========================================================================================
  129.  
  130. #ifdef FW_BUILD_MAC
  131. #pragma segment odflinking
  132. #endif
  133.  
  134. //========================================================================================
  135. //    class FW_CLinkManager
  136. //========================================================================================
  137.  
  138. FW_DEFINE_AUTO(FW_CLinkManager)
  139.  
  140. //---------------------------------------------------------------------------------------
  141. //    FW_CLinkManager constructor
  142. //---------------------------------------------------------------------------------------
  143.  
  144. FW_CLinkManager::FW_CLinkManager(Environment* ev, FW_CPart* thePart) :
  145.     fPart(thePart),
  146.     fPendingClipboardLink(NULL),
  147.     fPendingDropLink(NULL),
  148.     fSourceLinkList(NULL),
  149.     fDestLinkList(NULL)
  150. {
  151. FW_UNUSED(ev);
  152.     FW_END_CONSTRUCTOR
  153. }
  154.  
  155. //---------------------------------------------------------------------------------------
  156. //    FW_CLinkManager destructor
  157. //---------------------------------------------------------------------------------------
  158.  
  159. FW_CLinkManager::~FW_CLinkManager()
  160. {
  161.     FW_START_DESTRUCTOR
  162.     
  163.     delete fDestLinkList;
  164.     fDestLinkList = NULL;
  165.  
  166.     delete fSourceLinkList;
  167.     fSourceLinkList = NULL;
  168. }
  169.  
  170. //---------------------------------------------------------------------------------------
  171. //    FW_CLinkManager::RemoveAllLinks
  172. //---------------------------------------------------------------------------------------
  173.  
  174. void FW_CLinkManager::RemoveAllLinks(Environment* ev)
  175. {
  176. FW_UNUSED(ev);
  177.     // ----- Delete source links -----
  178.     if (fSourceLinkList)
  179.     {
  180.         FW_CLinkSource* link;
  181.         while ((link = fSourceLinkList->First()) != NULL)
  182.         {
  183.             fSourceLinkList->Remove(link);
  184.             delete link;
  185.         }        
  186.     }
  187.     
  188.     // ----- Delete destination links -----
  189.     if (fDestLinkList)
  190.     {
  191.         FW_CLinkDestination* link;
  192.         while ((link = fDestLinkList->First()) != NULL)
  193.         {
  194.             fDestLinkList->Remove(link);
  195.             delete link;
  196.         }        
  197.     }
  198. }
  199.  
  200. //---------------------------------------------------------------------------------------
  201. //    FW_CLinkManager::AddToSourceLinkList
  202. //---------------------------------------------------------------------------------------
  203.  
  204. void FW_CLinkManager::AddToSourceLinkList(Environment* ev, FW_CLinkSource* linkSource)
  205. {
  206. FW_UNUSED(ev);
  207.     if (fSourceLinkList == NULL)
  208.         fSourceLinkList = FW_NEW(FW_TOrderedCollection<FW_CLinkSource>, ());
  209.     else if (fSourceLinkList->Contains(linkSource))
  210.         return;
  211.     
  212.     fSourceLinkList->AddLast(linkSource);
  213. }
  214.  
  215. //---------------------------------------------------------------------------------------
  216. //    FW_CLinkManager::AddToDestLinkList
  217. //---------------------------------------------------------------------------------------
  218.  
  219. void FW_CLinkManager::AddToDestLinkList(Environment* ev, FW_CLinkDestination* linkDest)
  220. {
  221. FW_UNUSED(ev);
  222.     if (fDestLinkList == NULL)
  223.         fDestLinkList = FW_NEW(FW_TOrderedCollection<FW_CLinkDestination>, ());
  224.     else if (fDestLinkList->Contains(linkDest))
  225.         return;
  226.         
  227.     fDestLinkList->AddLast(linkDest);
  228. }
  229.  
  230. //---------------------------------------------------------------------------------------
  231. //    FW_CLinkManager::BreakSourceLink
  232. //---------------------------------------------------------------------------------------
  233. void FW_CLinkManager::BreakSourceLink(Environment* ev, FW_CLinkSource* linkSource)
  234. {
  235.     linkSource->BreakLink(ev);
  236.     this->RemoveFromSourceLinkList(ev, linkSource);
  237. }
  238.  
  239. //---------------------------------------------------------------------------------------
  240. //    FW_CLinkManager::BreakDestinationLink
  241. //---------------------------------------------------------------------------------------
  242. void FW_CLinkManager::BreakDestinationLink(Environment* ev, FW_CLinkDestination* linkDest)
  243. {
  244.     linkDest->BreakLink(ev);
  245.     this->RemoveFromDestLinkList(ev, linkDest);
  246. }
  247.  
  248. //---------------------------------------------------------------------------------------
  249. //    FW_CLinkManager::CountSourceLinks
  250. //---------------------------------------------------------------------------------------
  251.  
  252. unsigned long FW_CLinkManager::CountSourceLinks(Environment* ev) const
  253. {
  254. FW_UNUSED(ev);
  255.     if (fSourceLinkList)
  256.         return fSourceLinkList->Count();
  257.  
  258.     return 0;
  259. }
  260.  
  261. //---------------------------------------------------------------------------------------
  262. //    FW_CLinkManager::CountDestinationLinks
  263. //---------------------------------------------------------------------------------------
  264.  
  265. unsigned long FW_CLinkManager::CountDestinationLinks(Environment* ev) const
  266. {
  267. FW_UNUSED(ev);
  268.     if (fDestLinkList)
  269.         return fDestLinkList->Count();
  270.  
  271.     return 0;
  272. }
  273.  
  274. //---------------------------------------------------------------------------------------
  275. //    FW_CLinkManager::CreateLink
  276. //---------------------------------------------------------------------------------------
  277.  
  278. ODLinkSource* FW_CLinkManager::CreateLink(Environment* ev, ODByteArray* data)
  279. {
  280.     ODLinkSource* odLinkSource = NULL;
  281.     ODUpdateID updateID = *((ODUpdateID*)(data->_buffer));
  282.  
  283.     // The link spec is either on the clipboard or saved from a Drag&Drop operation.
  284.     // Determine which one to use by checking the ids
  285.     FW_Boolean linkSpecOnClipboard = true;
  286.  
  287.     // --- Check the clipboard link spec first, since it's the most likely candidate ---
  288.     FW_CLinkSource* pendingLink = this->GetPendingClipboardLink(ev);
  289.     if (pendingLink && (pendingLink->GetPendingID(ev) == updateID))
  290.     {
  291.         // Get the link if it already exists
  292.         odLinkSource = pendingLink->GetODLinkSource(ev);
  293.     }
  294.     else    // check for a Drag&Drop link spec
  295.     {
  296.         pendingLink = this->GetPendingDropLink(ev);
  297.         FW_ASSERT(pendingLink != NULL);
  298.         FW_ASSERT(pendingLink->GetPendingID(ev) == updateID);
  299.         linkSpecOnClipboard = false;
  300.  
  301.         // The Drag&Drop link spec is only good for creating one link
  302.         this->PrivSetPendingDropLink(ev, NULL);
  303.     }
  304.  
  305.     if (odLinkSource == NULL)        // link does not yet exist
  306.     {
  307.         FW_CPrivCreateLinkSourceCommand* cmd = pendingLink->PrivGetPendingCommand(ev);
  308.         FW_Boolean cmdExecuted = true;
  309.  
  310.         FW_TRY
  311.         {
  312.             if (!cmd)
  313.             {
  314.                 FW_CFrame* frame = fPart->GetLastActiveFrame(ev);    /* ??? */
  315.                 cmd = FW_NEW(FW_CPrivCreateLinkSourceCommand, (ev, frame, this, pendingLink));
  316.                 cmdExecuted = cmd->Execute(ev);
  317.             }
  318.             else
  319.             {
  320.                 cmd->SetLinkSource(ev, pendingLink);
  321.             }
  322.         
  323.             if (cmdExecuted)
  324.             {
  325.                 odLinkSource = cmd->GetODLinkSource(ev);
  326.                 // Don't DeletePendingClipboardLink, because more links may be created from it
  327.             }
  328.             // else cmd has been deleted
  329.         }
  330.         FW_CATCH_BEGIN
  331.         FW_CATCH_EVERYTHING() 
  332.         {
  333.             // $$$$$ [MH] I don't think that this should be trapped!
  334.             // Perhaps returning a null ODLinkSource is sufficient, but
  335.             // the failure must propagate to the intended destination.
  336.             
  337.             // don't re-throw; odLinkSource remains NULL
  338.         }
  339.         FW_CATCH_END
  340.     }
  341.     else
  342.     {
  343.         pendingLink->ContentUpdated(ev, kODUnknownUpdate, TRUE);
  344.         odLinkSource->Acquire(ev);
  345.     }
  346.         
  347.     return odLinkSource;
  348. }
  349.  
  350. //---------------------------------------------------------------------------------------
  351. //    FW_CLinkManager::DeletePendingClipboardLink
  352. //---------------------------------------------------------------------------------------
  353.  
  354. void FW_CLinkManager::DeletePendingClipboardLink(Environment* ev)
  355. {
  356.     if (fPendingClipboardLink != NULL)
  357.     {
  358.         ODClipboard* clipboard = FW_CSession::GetClipboard(ev);
  359.         
  360.         if (fPendingClipboardLink->GetPendingID(ev) == clipboard->GetUpdateID(ev)) 
  361.         {
  362.             ODStorageUnit* clipboardSU = clipboard->GetContentStorageUnit(ev);
  363.             if (clipboardSU->Exists(ev, kODPropLinkSpec, (ODValueType) NULL, 0) == TRUE) 
  364.             {
  365.                 clipboardSU->Focus(ev, kODPropLinkSpec, kODPosUndefined, (ODValueType) NULL, 0, kODPosUndefined);
  366.                 clipboardSU->Remove(ev);
  367.             }
  368.         }
  369.         
  370.         if (fPendingClipboardLink->IsPending(ev))    // CreateLink was never called
  371.             delete fPendingClipboardLink;
  372.  
  373.         fPendingClipboardLink = NULL;
  374.     }
  375. }
  376.  
  377. //---------------------------------------------------------------------------------------
  378. //    FW_CLinkManager::DoChangeLinkStatus
  379. //---------------------------------------------------------------------------------------
  380.  
  381. void FW_CLinkManager::DoChangeLinkStatus(Environment* ev, ODFrame* odFrame)
  382. {
  383. FW_UNUSED(ev);
  384. FW_UNUSED(odFrame); 
  385.     // Embedding parts should override to call ODFrame::ChangeLinkStatus for any 
  386.     // embedded frames that are involved in a link when a link is created, broken, moved, etc.
  387.     // odFrame is the frame whose link status has changed.
  388. }
  389.  
  390. //---------------------------------------------------------------------------------------
  391. //    FW_CLinkManager::DoUpdateLinks
  392. //---------------------------------------------------------------------------------------
  393.  
  394. void FW_CLinkManager::DoUpdateLinks(Environment* ev,
  395.                                     ODFrame* odEmbeddedFrame,
  396.                                     ODUpdateID updateID)
  397. {
  398.     // An embedded frame has changed. (Formerly named EmbeddedFrameUpdated)
  399.     // If odEmbeddedFrame is involved in one of my link sources, update the link with new data.
  400.  
  401.     if (this->CountSourceLinks(ev) > 0)
  402.     {
  403.         FW_CLinkMgrLinkSourceIterator iter(this);
  404.         for (FW_CLinkSource* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
  405.         {
  406.             if (link->HasEmbeddedFrame(ev, odEmbeddedFrame))
  407.             {
  408.                 link->ContentUpdated(ev, updateID, FALSE);
  409.                 break;
  410.             }
  411.         }
  412.     }
  413. }
  414.  
  415. //---------------------------------------------------------------------------------------
  416. //    FW_CLinkManager::EditInLinkAttempted
  417. //---------------------------------------------------------------------------------------
  418.  
  419. FW_Boolean FW_CLinkManager::EditInLinkAttempted(Environment* ev, ODFrame* odFrame)
  420. {
  421.     // --- Is there a link destination involving odFrame?
  422.     FW_CLinkDestination* linkDest = NULL;
  423.     FW_CFrame* frame = NULL;
  424.     if (this->CountDestinationLinks(ev) > 0)
  425.     {
  426.         FW_CLinkMgrLinkDestIterator it(this);
  427.         for (FW_CLinkDestination* link = it.First(); it.IsNotComplete(); link = it.Next())
  428.         {
  429.             frame = link->GetContainingFrame(ev, odFrame);
  430.             if (frame != NULL)
  431.             {
  432.                 linkDest = link;
  433.                 break;
  434.             }
  435.         }
  436.     }
  437.  
  438.     if (linkDest == NULL)    // can't find the link
  439.         return false;
  440.  
  441.     EditInLinkAlert(ev, linkDest, frame);
  442.     return true;
  443. }
  444.  
  445. //---------------------------------------------------------------------------------------
  446. //    FW_CLinkManager::EditInLinkAlert
  447. //---------------------------------------------------------------------------------------
  448. FW_Boolean FW_CLinkManager::EditInLinkAlert(Environment* ev, FW_CLinkDestination* linkDest, FW_CFrame* frame)
  449. {
  450.     // We need to be in front to show the dlg. If we're not
  451.     // then the attempt to edit must be drop into a backround doc.
  452.     // we can't come to the front during a drop (I've tried it, nothing
  453.     // happens), so we'll just return false in that case.  If we could defer putting the dlg
  454.     // up, then we would come to the front after the drop completes, but that does no good
  455.     // since we have to determine whether to accept the drop or not now.
  456.     
  457.     FW_ASSERT(frame);
  458.         
  459.     if (!frame->GetWindow(ev)->IsActive(ev))
  460.         return false;        
  461.  
  462.     // Present alert box to user with 3 choices: Find Source, Break Link, or Cancel
  463.     // Return TRUE if user chooses to break the link so that she can edit
  464.     short reply = PrivShowEditInLinkAlert(ev);
  465.     if (reply == FW_kFindSourceButtonID)
  466.     {
  467.         this->PrivShowLinkSource(ev, linkDest);
  468.     }
  469.     else if (reply == FW_kBreakLinkButtonID)
  470.     {
  471.         FW_CBreakLinkCommand* cmd = FW_NEW(FW_CBreakLinkCommand, (ev, frame, linkDest, this));
  472.         cmd->Execute(ev);
  473.     }
  474.     // else reply == FW_kCancelEditButtonID, so just return
  475.  
  476.     return (reply == FW_kBreakLinkButtonID);
  477. }
  478.  
  479. //---------------------------------------------------------------------------------------
  480. //    FW_CLinkManager::ODtoFWLinkSource
  481. //---------------------------------------------------------------------------------------
  482.  
  483. FW_CLinkSource* FW_CLinkManager::ODtoFWLinkSource(Environment* ev, ODLinkSource* odLinkSource) const
  484. {
  485.     FW_TOrderedCollectionIterator<FW_CLinkSource> iter(fSourceLinkList);
  486.     for (FW_CLinkSource* link = iter.First(); iter.IsNotComplete(); link = iter.Next()) 
  487.     {
  488.         if (odLinkSource->IsEqualTo(ev, link->GetODLinkSource(ev)))
  489.             return link;
  490.     }
  491.     return NULL;
  492. }
  493.  
  494. //---------------------------------------------------------------------------------------
  495. //    FW_CLinkManager::ODtoFWLink
  496. //---------------------------------------------------------------------------------------
  497.  
  498. FW_CLinkDestination* FW_CLinkManager::ODtoFWLink(Environment* ev, ODLink* odLink) const
  499. {
  500.     FW_TOrderedCollectionIterator<FW_CLinkDestination> iter(fDestLinkList);
  501.     for (FW_CLinkDestination* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
  502.     {
  503.         if (odLink->IsEqualTo(ev, link->GetODLink(ev)))
  504.             return link;
  505.     }
  506.     return NULL;
  507. }
  508.  
  509. //---------------------------------------------------------------------------------------
  510. //    FW_CLinkManager::RevealLink
  511. //---------------------------------------------------------------------------------------
  512.  
  513. void FW_CLinkManager::RevealLink(Environment* ev, ODLinkSource* odLinkSource)
  514. {
  515.     FW_CLinkSource* sourceLink = ODtoFWLinkSource(ev, odLinkSource);
  516.     if (sourceLink == NULL)        // can't find link
  517.         return;
  518.  
  519.     // Choose a display frame for the source content
  520.     FW_CFrame* frame = sourceLink->GetFrameToRevealLink(ev);    // part-specific
  521.     if (frame)
  522.     {
  523.         // ----- Activate the frame's window -----
  524.         if (!frame->GetWindow(ev)->IsActive(ev))
  525.             frame->GetWindow(ev)->Select(ev);        
  526.     
  527.         // ----- Activate the frame -----
  528.         if (!frame->HasSelectionFocus(ev))
  529.         {
  530.             frame->ActivateFrame(ev, NULL);
  531.             
  532. //            FW_CFrameFacetIterator iter(ev, frame);    // find a facet
  533. //            frame->ActivateFrame(ev, iter.First(ev));
  534.         }
  535.  
  536.         // ----- Tell the link source to reveal its content -----
  537.         sourceLink->RevealLinkSource(ev, frame);
  538.     }
  539. }
  540.  
  541. //---------------------------------------------------------------------------------------
  542. //    FW_CLinkManager::RemoveFromSourceLinkList
  543. //---------------------------------------------------------------------------------------
  544.  
  545. void FW_CLinkManager::RemoveFromSourceLinkList(Environment* ev, FW_CLinkSource* linkSource)
  546. {
  547.     if (fSourceLinkList)
  548.     {
  549.         fSourceLinkList->Remove(linkSource);
  550.     
  551.         if (linkSource == fPendingClipboardLink)
  552.             this->DeletePendingClipboardLink(ev);
  553.         
  554.         if (fSourceLinkList->Count() == 0)
  555.         {
  556.             delete fSourceLinkList;
  557.             fSourceLinkList = NULL;
  558.         }
  559.     }
  560. }
  561.  
  562. //---------------------------------------------------------------------------------------
  563. //    FW_CLinkManager::RemoveFromDestLinkList
  564. //---------------------------------------------------------------------------------------
  565.  
  566. void FW_CLinkManager::RemoveFromDestLinkList(Environment* ev, FW_CLinkDestination* linkDest)
  567. {
  568. FW_UNUSED(ev);
  569.  
  570.     if (fDestLinkList)
  571.     {
  572.         fDestLinkList->Remove(linkDest);
  573.         
  574.         if (fDestLinkList->Count() == 0)
  575.         {
  576.             delete fDestLinkList;
  577.             fDestLinkList = NULL;
  578.         }
  579.     }
  580. }
  581.  
  582. //---------------------------------------------------------------------------------------
  583. //    FW_CLinkManager::RestoreSourceLink
  584. //---------------------------------------------------------------------------------------
  585. void FW_CLinkManager::RestoreSourceLink(Environment* ev, FW_CLinkSource* linkSource)
  586. {
  587.     this->AddToSourceLinkList(ev, linkSource);
  588.     linkSource->RestoreLink(ev, fPart);
  589. }
  590.  
  591. //---------------------------------------------------------------------------------------
  592. //    FW_CLinkManager::RestoreDestinationLink
  593. //---------------------------------------------------------------------------------------
  594. void FW_CLinkManager::RestoreDestinationLink(Environment* ev, FW_CLinkDestination* linkDest)
  595. {
  596.     this->AddToDestLinkList(ev, linkDest);
  597.     linkDest->RestoreLink(ev, fPart);
  598.     linkDest->PrivEstablishLink(ev);
  599. }
  600.  
  601. //---------------------------------------------------------------------------------------
  602. //    FW_CLinkManager::PasteWithLink
  603. //---------------------------------------------------------------------------------------
  604. FW_CLinkDestination* FW_CLinkManager::PasteWithLink(Environment* ev, ODStorageUnit* storageUnit, 
  605.                                                     ODPasteAsResult& pasteAsResult,
  606.                                                     FW_CFrame* frame,
  607.                                                     FW_StorageKinds storageKind)
  608. {
  609.     FW_CLinkDestination* linkDest = NULL;
  610.     ODLinkSpec* linkSpec = NULL;
  611.     ODLink* odLink = NULL;
  612.     ODDraft* draft = fPart->GetDraft(ev);
  613.     if (!storageUnit->Exists(ev, kODPropLinkSpec, (ODValueType)NULL, 0))
  614.         return linkDest;
  615.  
  616.     FW_CPrivCreateLinkCommand* cmd = NULL;
  617.     FW_VOLATILE(cmd);
  618.     FW_VOLATILE(linkSpec);
  619.     FW_VOLATILE(odLink);
  620.  
  621.     FW_TRY
  622.     {
  623.         linkSpec = draft->CreateLinkSpec(ev, NULL, NULL);
  624.  
  625.         storageUnit->Focus(ev, kODPropLinkSpec, kODPosUndefined, (ODValueType)NULL, 0, kODPosUndefined);
  626.         linkSpec->ReadLinkSpec(ev, storageUnit);
  627.  
  628.         // ---- Write a transaction to the Undo history ----
  629.         cmd = FW_NEW(FW_CPrivCreateLinkCommand, (ev, frame, this, storageKind == FW_kClipboardStorage));
  630.         cmd->Execute(ev);
  631.  
  632.         // ---- Establish the Link ----
  633.         odLink = draft->AcquireLink(ev, (ODStorageUnitID)0, linkSpec);    // use linkSpec to retrieve the link
  634.  
  635.         if (odLink)
  636.         {
  637.             // --- Embed or incorporate the link ---
  638.             linkDest = this->PrivMakeLink(ev, odLink, pasteAsResult, frame->GetPresentation(ev));
  639.             cmd->SetLink(ev, linkDest);
  640.             odLink->Release(ev);    // to balance AcquireLink
  641.         }
  642.     }
  643.     FW_CATCH_BEGIN
  644.     FW_CATCH_EVERYTHING()
  645.     {
  646.         if (linkSpec)
  647.             delete linkSpec;
  648.         if (odLink)
  649.             odLink->Release(ev);
  650.         if (cmd)
  651.             delete cmd;
  652.         FW_THROW_SAME();
  653.     }
  654.     FW_CATCH_END
  655.  
  656.     if (linkSpec)
  657.         delete linkSpec;
  658.                     
  659.     return linkDest;
  660. }
  661.  
  662. //---------------------------------------------------------------------------------------
  663. //    FW_CLinkManager::PrivMakeLink
  664. //---------------------------------------------------------------------------------------
  665. FW_CLinkDestination* FW_CLinkManager::PrivMakeLink(Environment* ev,
  666.                                                    ODLink* odLink,
  667.                                                    ODPasteAsResult& pasteAsResult,
  668.                                                    FW_CPresentation* presentation)
  669. {
  670.     FW_CLinkDestination* linkDest = NULL;
  671.     FW_VOLATILE(linkDest);
  672.  
  673.     FW_TRY
  674.     {
  675.         ODLinkInfo linkInfo;
  676.         linkInfo.change = kODUnknownUpdate;            // not yet updated
  677.         FW_CTime time = FW_CTime::GetCurrentTime();
  678.         linkInfo.creationTime = time.GetTime();
  679.         linkInfo.changeTime = linkInfo.creationTime;
  680.         linkInfo.autoUpdate = pasteAsResult.autoUpdateSetting;
  681.         linkInfo.kind = NULL;
  682.  
  683.         linkDest = this->NewLinkDestination(ev, odLink, &linkInfo, presentation);
  684.         this->AddToDestLinkList(ev, linkDest);
  685.         linkDest->SavePasteAsSettings(ev, pasteAsResult);
  686.  
  687.         linkDest->Register(ev, fPart);    // causes LinkUpdated to be called
  688.         if (linkDest->GetUpdateID(ev) != kODUnknownUpdate)    // LinkUpdated succeeded
  689.             linkDest->PrivEstablishLink(ev);
  690.     }
  691.     FW_CATCH_BEGIN
  692.     FW_CATCH_EVERYTHING()
  693.     {
  694.         if (linkDest)
  695.         {
  696.             this->RemoveFromDestLinkList(ev, linkDest);
  697.             delete linkDest;
  698.         }
  699.         FW_THROW_SAME();
  700.     }
  701.     FW_CATCH_END
  702.  
  703.     return linkDest;
  704. }
  705.  
  706. //---------------------------------------------------------------------------------------
  707. //    FW_CLinkManager::ExternalizeLinks
  708. //---------------------------------------------------------------------------------------
  709. void FW_CLinkManager::ExternalizeLinks(Environment* ev, ODStorageUnit* su,
  710.                                        FW_CCloneInfo* cloneInfo)
  711. {
  712.     // If we're cloning into a link, OpenDoc will return an invalid ID for each link 
  713.     // when we try to clone it. So don't try to clone it.
  714.     if (cloneInfo != NULL && cloneInfo->GetCloneKind(ev) == kODCloneToLink)
  715.         return;
  716.  
  717.     //--- Write out the source links ---
  718.     if (this->CountSourceLinks(ev) > 0)
  719.     {
  720.         //-- Make sure the value is present in the SU --
  721.         FW_SUForceFocus(ev, su, kODPropContents, this->GetSourceLinkFormat(ev));
  722.  
  723.         FW_CLinkMgrLinkSourceIterator iter(this);
  724.         for (FW_CLinkSource* slink = iter.First(); iter.IsNotComplete(); slink = iter.Next())
  725.         {
  726.             slink->ExternalizeLink(ev, su, cloneInfo);
  727.         }
  728.     }
  729.  
  730.     //--- Write out the destination links ---
  731.     if (this->CountDestinationLinks(ev) > 0)
  732.     {
  733.         //-- Make sure the value is present in the SU --
  734.         FW_SUForceFocus(ev, su, kODPropContents, this->GetDestLinkFormat(ev));
  735.  
  736.         FW_CLinkMgrLinkDestIterator iter(this);
  737.         for (FW_CLinkDestination* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
  738.         {
  739.             link->ExternalizeLink(ev, su, cloneInfo);
  740.         }
  741.     }
  742. }
  743.  
  744. //---------------------------------------------------------------------------------------
  745. //    FW_CLinkManager::InternalizeLinks
  746. //---------------------------------------------------------------------------------------
  747. void FW_CLinkManager::InternalizeLinks(Environment* ev, ODStorageUnit* storageUnit)
  748. {
  749.     unsigned long valueSize;
  750.  
  751.     if (FW_SUExistsThenFocus(ev, storageUnit, kODPropContents, this->GetSourceLinkFormat(ev)))
  752.     {
  753.         valueSize = storageUnit->GetSize(ev);
  754.         while (storageUnit->GetOffset(ev) < valueSize)
  755.         {
  756.             this->PrivInternalizeOneSourceLink(ev, storageUnit);
  757.         }
  758.     }
  759.  
  760.     if (FW_SUExistsThenFocus(ev, storageUnit, kODPropContents, this->GetDestLinkFormat(ev)))
  761.     {
  762.         valueSize = storageUnit->GetSize(ev);
  763.         while (storageUnit->GetOffset(ev) < valueSize)
  764.         {
  765.             this->PrivInternalizeOneDestLink(ev, storageUnit);
  766.         }
  767.     }
  768. }
  769.  
  770. //---------------------------------------------------------------------------------------
  771. //    FW_CLinkManager::PrivInternalizeOneSourceLink
  772. //---------------------------------------------------------------------------------------
  773. void FW_CLinkManager::PrivInternalizeOneSourceLink(Environment* ev, ODStorageUnit* storageUnit)
  774. {
  775.     // Storage unit must be focused to correct property and value (linkSourceFormat)
  776.     ODStorageUnitRef suRef;
  777.     FW_CByteArray byteArray;
  778.     long version;
  779.  
  780.     //--- First check the link version number ---
  781.     storageUnit->GetValue(ev, sizeof(long), byteArray);
  782.     byteArray.CopyBuffer(&version, sizeof(long));
  783.     FW_ASSERT(version == FW_kLinkVersionNumber);
  784.  
  785.     //--- Read the link reference and validate it ---
  786.     storageUnit->GetValue(ev, sizeof(ODStorageUnitRef), byteArray);
  787.     byteArray.CopyBuffer(&suRef, sizeof(ODStorageUnitRef));
  788.     if (storageUnit->IsValidStorageUnitRef(ev, suRef))
  789.     {
  790.         ODID linkID = storageUnit->GetIDFromStorageUnitRef(ev, suRef);
  791.         this->InternalizeSourceLink(ev, linkID, storageUnit);
  792.     }
  793. }
  794.  
  795. //---------------------------------------------------------------------------------------
  796. //    FW_CLinkManager::PrivInternalizeOneDestLink
  797. //---------------------------------------------------------------------------------------
  798. void FW_CLinkManager::PrivInternalizeOneDestLink(Environment* ev, ODStorageUnit* storageUnit)
  799. {
  800.     // Storage unit must be focused to correct property and value (linkDestFormat)
  801.     ODStorageUnitRef suRef;
  802.     FW_CByteArray byteArray;
  803.     long version;
  804.  
  805.     //--- First check the link version number ---
  806.     storageUnit->GetValue(ev, sizeof(long), byteArray);
  807.     byteArray.CopyBuffer(&version, sizeof(long));
  808.     FW_ASSERT(version == FW_kLinkVersionNumber);
  809.  
  810.     //--- Read the link reference and validate it ---
  811.     storageUnit->GetValue(ev, sizeof(ODStorageUnitRef), byteArray);
  812.     byteArray.CopyBuffer(&suRef, sizeof(ODStorageUnitRef));
  813.     if (storageUnit->IsValidStorageUnitRef(ev, suRef))
  814.     {
  815.         ODID linkID = storageUnit->GetIDFromStorageUnitRef(ev, suRef);
  816.         this->InternalizeDestLink(ev, linkID, storageUnit);
  817.     }
  818. }
  819.  
  820. //---------------------------------------------------------------------------------------
  821. //    FW_CLinkManager::DoInternalizeOneSourceLink
  822. //---------------------------------------------------------------------------------------
  823. FW_CLinkSource* FW_CLinkManager::DoInternalizeOneSourceLink(Environment* ev, 
  824.                                                              ODStorageUnit* storageUnit,
  825.                                                              ODUpdateID updateID)
  826. {
  827.     // Override to:
  828.     //    - read part-specific link source data from the storageUnit
  829.     //    - create and return a link source object
  830.  
  831. FW_UNUSED(ev);
  832. FW_UNUSED(storageUnit); 
  833. FW_UNUSED(updateID);
  834.     return NULL;
  835. }
  836.  
  837. //---------------------------------------------------------------------------------------
  838. //    FW_CLinkManager::DoInternalizeOneDestLink
  839. //---------------------------------------------------------------------------------------
  840. FW_CLinkDestination* FW_CLinkManager::DoInternalizeOneDestLink(Environment* ev, ODStorageUnit* storageUnit,
  841.                                                              ODLink* odLink, ODLinkInfo* linkInfo)
  842. {
  843.     // Override to:
  844.     //    - read part-specific link data from the storageUnit
  845.     //    - create and return a link destination object
  846.  
  847. FW_UNUSED(ev);
  848. FW_UNUSED(storageUnit); 
  849. FW_UNUSED(odLink); 
  850. FW_UNUSED(linkInfo); 
  851.     return NULL;
  852. }
  853.  
  854. //----------------------------------------------------------------------------------------
  855. //    FW_CLinkManager::RegisterLinks
  856. //----------------------------------------------------------------------------------------
  857. void FW_CLinkManager::RegisterLinks(Environment* ev)
  858. {
  859.     if (this->CountDestinationLinks(ev) > 0)
  860.     {
  861.         FW_CLinkMgrLinkDestIterator iter(this);
  862.         for (FW_CLinkDestination* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
  863.         {
  864.             link->Register(ev, fPart);    // auto-update link will have its LinkUpdated method called
  865.         }
  866.     }
  867. }
  868.  
  869. //----------------------------------------------------------------------------------------
  870. //    FW_CLinkManager::InternalizeSourceLink
  871. //----------------------------------------------------------------------------------------
  872. void FW_CLinkManager::InternalizeSourceLink(Environment* ev, ODID linkID,
  873.                                             ODStorageUnit* storageUnit)
  874. {
  875.     // Storage unit must be focused to correct property and value (linkSourceFormat)
  876.     // The linkID must be valid
  877.     ODUpdateID updateID;
  878.     FW_CByteArray byteArray;
  879.     ODDraft* myDraft = fPart->GetDraft(ev);
  880.  
  881.     //-- Read the link source data, using the validated ID
  882.     ODLinkSource* odLinkSource = myDraft->AcquireLinkSource(ev, linkID);
  883.     storageUnit->GetValue(ev, sizeof(ODUpdateID), byteArray);
  884.     byteArray.CopyBuffer(&updateID, sizeof(ODUpdateID));
  885.  
  886.     //-- Read the link source data (part-specific)
  887.     FW_CLinkSource* linkSource = this->DoInternalizeOneSourceLink(ev, storageUnit, updateID);
  888.     if (linkSource)
  889.     {
  890.         //-- Ensure the link source object references our part as the source of the link
  891.         odLinkSource->SetSourcePart(ev, fPart->GetStorageUnit(ev));
  892.  
  893.         linkSource->SetODLinkSource(ev, odLinkSource);
  894.         this->AddToSourceLinkList(ev, linkSource);
  895.     }
  896.  
  897.     odLinkSource->Release(ev);    // to balance AcquireLinkSource above
  898. }
  899.  
  900. //----------------------------------------------------------------------------------------
  901. //    FW_CLinkManager::InternalizeDestLink
  902. //----------------------------------------------------------------------------------------
  903. void FW_CLinkManager::InternalizeDestLink(Environment* ev, ODID linkID,
  904.                                           ODStorageUnit* storageUnit)
  905. {
  906.     // Storage unit must be focused to correct property and value (linkDestFormat)
  907.     // The linkID must be valid
  908.     ODLinkInfo linkInfo;
  909.     ODPasteAsResult embedInfo;
  910.     FW_CByteArray byteArray;
  911.     ODDraft* myDraft = fPart->GetDraft(ev);
  912.  
  913.     //-- Acquire the link, using the validated ID
  914.     ODLink* odLink = myDraft->AcquireLink(ev, linkID, NULL);
  915.  
  916.     //--- Read the link info and kind ---
  917.     storageUnit->GetValue(ev, sizeof(ODLinkInfo), byteArray);
  918.     byteArray.CopyBuffer(&linkInfo, sizeof(ODLinkInfo));
  919.     // Allocate space for the kind string (its size is in linkInfo.kind)
  920.     ODType kind = (ODType) FW_CMemoryManager::AllocateBlock((ODULong)linkInfo.kind);
  921.     storageUnit->GetValue(ev, (ODULong)linkInfo.kind, byteArray);
  922.     byteArray.CopyBuffer((void*)kind, (ODULong)linkInfo.kind);
  923.     linkInfo.kind = NULL;
  924.  
  925.     //--- Read the Paste As info, if there is any ---
  926.     FW_Boolean hasEmbedInfo;
  927.     storageUnit->GetValue(ev, sizeof(FW_Boolean), byteArray);
  928.     byteArray.CopyBuffer(&hasEmbedInfo, sizeof(FW_Boolean));
  929.     if (hasEmbedInfo)
  930.     {
  931.         // Read embedInfo struct
  932.         storageUnit->GetValue(ev, sizeof(ODPasteAsResult), byteArray);
  933.         byteArray.CopyBuffer(&embedInfo, sizeof(ODPasteAsResult));
  934.         // Get selectedKind string from link info
  935.         embedInfo.selectedKind = kind;
  936.         // Read translateKind string, if there is one
  937.         if (embedInfo.translateKind != 0)
  938.         {
  939.             kind = (ODType) FW_CMemoryManager::AllocateBlock((ODULong)embedInfo.translateKind);
  940.             storageUnit->GetValue(ev, (ODULong)embedInfo.translateKind, byteArray);
  941.             byteArray.CopyBuffer((void*)kind, (ODULong)embedInfo.translateKind);
  942.             embedInfo.translateKind = kind;
  943.         }
  944.         // Read editor string, if there is one
  945.         if (embedInfo.editor != 0)
  946.         {
  947.             ODEditor temp = (ODEditor) FW_CMemoryManager::AllocateBlock((ODULong)embedInfo.editor);
  948.             storageUnit->GetValue(ev, (ODULong)embedInfo.editor, byteArray);
  949.             byteArray.CopyBuffer((void*)temp, (ODULong)embedInfo.editor);
  950.             embedInfo.editor = temp;
  951.         }
  952.     }
  953.     else    // SU contains no embed info; initialize fields in the struct to reflect this
  954.     {
  955.         embedInfo.mergeSetting = kODTrue;    // no embedding
  956.         embedInfo.selectedKind = kind;
  957.         embedInfo.translateKind = NULL;
  958.         embedInfo.editor = NULL;
  959.     }
  960.  
  961.     //-- Read the part-specific link data
  962.     FW_CLinkDestination* destLink = this->DoInternalizeOneDestLink(ev, storageUnit, odLink, &linkInfo);
  963.     if (destLink)
  964.     {
  965.         //-- Establish the link
  966.         this->AddToDestLinkList(ev, destLink);
  967.         destLink->SavePasteAsSettings(ev, embedInfo);
  968.         destLink->PrivEstablishLink(ev);
  969.     }
  970.  
  971.     odLink->Release(ev);    // to balance AcquireLink above
  972. }
  973.  
  974. //----------------------------------------------------------------------------------------
  975. //    FW_CLinkManager::PrivShowLinkSource
  976. //----------------------------------------------------------------------------------------
  977. void FW_CLinkManager::PrivShowLinkSource(Environment* ev, FW_CLinkDestination* link)
  978. {
  979.     FW_Boolean foundSource = true;
  980.     FW_VOLATILE(foundSource);
  981.  
  982.     FW_TRY
  983.     {
  984.         link->GetODLink(ev)->ShowSourceContent(ev);
  985.     }
  986.     FW_CATCH_BEGIN
  987.     FW_CATCH_REFERENCE(FW_XException, ex)
  988.     {
  989.         foundSource = false;    // don't re-throw; we'll handle the exception
  990.     }
  991.     FW_CATCH_END
  992.  
  993.     if (!foundSource)
  994.     {
  995.         // If ShowSourceContent throws an exception, display an alert message
  996.         // informing the user that the link-source content could not be shown.
  997.         fPart->PrivShowErrorAlert(ev, FW_kLinkingStrings, FW_kCantFindLinkSourceMsg);
  998.     }
  999. }
  1000.  
  1001. //----------------------------------------------------------------------------------------
  1002. #ifdef FW_BUILD_MAC
  1003.  
  1004. static pascal Boolean MacEditInLinkAlertFilter(DialogPtr theDialog, 
  1005.                                                EventRecord * theEvent, 
  1006.                                                short *itemHit);
  1007.  
  1008. #endif
  1009.  
  1010. //----------------------------------------------------------------------------------------
  1011. //    FW_CLinkManager::PrivShowEditInLinkAlert
  1012. //----------------------------------------------------------------------------------------
  1013. short FW_CLinkManager::PrivShowEditInLinkAlert(Environment* ev)
  1014. {
  1015.     
  1016. #ifdef FW_BUILD_MAC
  1017.     ModalFilterUPP filterProc = NewModalFilterProc(&MacEditInLinkAlertFilter);
  1018.  
  1019.     FW_PSharedLibraryResourceFile resFile(ev);
  1020.     short item = Alert(FW_kMacEditInLinkDialog, filterProc);
  1021.         
  1022.     DisposeRoutineDescriptor(filterProc);
  1023.     return item;
  1024. #endif
  1025. #ifdef FW_BUILD_WIN
  1026.     // Not yet implemented
  1027. #endif
  1028. }
  1029.  
  1030. //----------------------------------------------------------------------------------------
  1031. //    MacEditInLinkAlertFilter
  1032. //----------------------------------------------------------------------------------------
  1033. #ifdef FW_BUILD_MAC
  1034. static pascal Boolean MacEditInLinkAlertFilter(DialogPtr theDialog, 
  1035.                                                EventRecord * theEvent, 
  1036.                                                short *itemHit)
  1037. {
  1038.     Boolean result = FALSE;
  1039.  
  1040.     switch (theEvent->what)
  1041.     {
  1042.         case keyDown:
  1043.         case autoKey:
  1044.             {
  1045.                 switch (theEvent->message & charCodeMask)
  1046.                 {
  1047.                     case '.':
  1048.                         if (theEvent->modifiers & cmdKey)
  1049.                         {
  1050.                             result = TRUE;
  1051.                             *itemHit = FW_kCancelEditButtonID;
  1052.                         }
  1053.                         break;
  1054.                     
  1055.                     case 0x0D:
  1056.                     case 0x03:
  1057.                         result = TRUE;
  1058.                         *itemHit = FW_kFindSourceButtonID;
  1059.                         break;
  1060.                     
  1061.                     case 0x1B:
  1062.                         result = TRUE;
  1063.                         *itemHit = FW_kCancelEditButtonID;
  1064.                         break;                
  1065.                 }
  1066.                 
  1067.                 if (result)        // flash the button
  1068.                 {
  1069.                     long     theTick;
  1070.                     short     itemType;
  1071.                     Handle     hItem;
  1072.                     Rect    box;
  1073.                     
  1074.                     ::GetDialogItem(theDialog, *itemHit, &itemType, &hItem, &box);
  1075.                     ::HiliteControl((ControlHandle)hItem, 1);
  1076.                     ::Delay(6,&theTick);
  1077.                     ::HiliteControl((ControlHandle)hItem, 0);            
  1078.                 }
  1079.             }
  1080.             break;
  1081.         
  1082.         case updateEvt:
  1083.             if (theDialog == (DialogPtr)theEvent->message)
  1084.             {
  1085.                 PenState     ps;
  1086.                 Rect        box;
  1087.                 Handle        handle;
  1088.                 short        type;
  1089.                 
  1090.                 ::SetPort(theDialog);
  1091.                 ::GetPenState(&ps);
  1092.                 ::PenSize(3, 3);
  1093.                 ::GetDialogItem(theDialog, FW_kFindSourceButtonID, &type, &handle, &box);
  1094.                 ::InsetRect(&box, -4, -4);
  1095.                 ::FrameRoundRect(&box, 16, 16);
  1096.                 ::SetPenState(&ps);
  1097.             }
  1098.             break;
  1099.     }
  1100.  
  1101.     return result;
  1102. }
  1103. #endif
  1104.  
  1105. //----------------------------------------------------------------------------------------
  1106. //    FW_CLinkManager::GetLinkInfoString
  1107. //----------------------------------------------------------------------------------------
  1108. FW_Boolean FW_CLinkManager::GetLinkInfoString(Environment* ev, FW_CString& infoString)
  1109. {
  1110.     // If a link is selected, set infoString to the default Link Info string and return true.
  1111.     FW_CLink* selectedLink = this->GetSelectedLink(ev);
  1112.     if (selectedLink)
  1113.     {
  1114.         ::FW_PrivLoadODFString(ev, FW_kLinkInfoString, infoString);
  1115.         return true;
  1116.     }
  1117.  
  1118.     return false;
  1119. }
  1120.  
  1121. //----------------------------------------------------------------------------------------
  1122. //    FW_CLinkManager::ShowLinkInfo
  1123. //----------------------------------------------------------------------------------------
  1124. FW_Boolean FW_CLinkManager::ShowLinkInfo(Environment* ev, FW_CFrame* frame)
  1125. {
  1126.     // If a link is selected, put up the Link Info dialog, handle it, and return true.
  1127.     // Return false if no links are selected.
  1128.  
  1129.     if (this->CountDestinationLinks(ev) > 0)
  1130.     {
  1131.         FW_CLinkMgrLinkDestIterator iter(this);
  1132.         for (FW_CLinkDestination* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
  1133.         {
  1134.             if (link->IsLinkSelected(ev))
  1135.             {
  1136.                 link->ShowLinkInfo(ev, frame, this);
  1137.                 return true;
  1138.             }
  1139.         }
  1140.     }
  1141.  
  1142.     if (this->CountSourceLinks(ev) > 0)
  1143.     {
  1144.         FW_CLinkMgrLinkSourceIterator iter(this);
  1145.         for (FW_CLinkSource* slink = iter.First(); iter.IsNotComplete(); slink = iter.Next())
  1146.         {
  1147.             if (slink->IsLinkSelected(ev))
  1148.             {
  1149.                 slink->ShowLinkInfo(ev, frame, this);
  1150.                 return true;
  1151.             }
  1152.         }
  1153.     }
  1154.  
  1155.     return false;
  1156. }
  1157.  
  1158. //----------------------------------------------------------------------------------------
  1159. //    FW_CLinkManager::GetSelectedLink
  1160. //----------------------------------------------------------------------------------------
  1161. FW_CLink* FW_CLinkManager::GetSelectedLink(Environment* ev)
  1162. {
  1163.     FW_CLinkIterator it(this);
  1164.     for (FW_CLink* link = it.FirstLink(); it.IsNotComplete(); link = it.NextLink())
  1165.     {
  1166.         if (link->IsLinkSelected(ev))
  1167.         {
  1168.             return link;
  1169.         }
  1170.     }
  1171.     return NULL;
  1172. }
  1173.  
  1174. //----------------------------------------------------------------------------------------
  1175. //    FW_CLinkManager::SelectLink
  1176. //----------------------------------------------------------------------------------------
  1177. void FW_CLinkManager::SelectLink(Environment* ev, FW_CLink* link)
  1178. {
  1179.     //--- If a different link is currently selected, de-select it
  1180.     FW_CLink* selectedLink = this->GetSelectedLink(ev);
  1181.     if (selectedLink && selectedLink != link)
  1182.     {
  1183.         selectedLink->Select(ev, false);
  1184.         selectedLink->InvalidateBorder(ev);
  1185.     }
  1186.  
  1187.     //--- Select the link
  1188.     link->Select(ev, true);
  1189.     link->InvalidateBorder(ev);
  1190. }
  1191.  
  1192. //----------------------------------------------------------------------------------------
  1193. //    FW_CLinkManager::SetPendingDropLink
  1194. //----------------------------------------------------------------------------------------
  1195. void FW_CLinkManager::PrivSetPendingDropLink(Environment* ev, FW_CLinkSource* linkSource, FW_CFrame* scopeFrame)
  1196. {
  1197.     FW_ASSERT(linkSource == NULL || scopeFrame != NULL);
  1198.     
  1199.     fPendingDropLink = linkSource;
  1200.     
  1201.     if (linkSource)
  1202.     {
  1203.         FW_CPrivCreateLinkSourceCommand* cmd = FW_NEW(FW_CPrivCreateLinkSourceCommand, (ev, scopeFrame, this, NULL));
  1204.         if (cmd->Execute(ev))  // with a null link, just posts the transaction
  1205.             linkSource->PrivSetPendingCommand(ev, cmd);
  1206.     }
  1207. }
  1208.  
  1209.